Skip to content

Webhooks and events#72

Open
QuackieMackie wants to merge 2 commits intoxenforo-ltd:mainfrom
QuackieMackie:webhooks
Open

Webhooks and events#72
QuackieMackie wants to merge 2 commits intoxenforo-ltd:mainfrom
QuackieMackie:webhooks

Conversation

@QuackieMackie
Copy link
Copy Markdown
Contributor

@QuackieMackie QuackieMackie commented Sep 21, 2025

Summary by CodeRabbit

Documentation

  • Added comprehensive developer guide covering webhook implementation for custom content types, including database structure setup, entity creation, content type registration, webhook event handler development for standard CRUD operations and custom events, and API result data configuration.
  • Updated navigation to feature the new webhook and events documentation within the Developer section under Advanced concepts for improved discoverability.

✏️ Tip: You can customize this high-level summary in your review settings.

@QuackieMackie
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 18, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 18, 2026

📝 Walkthrough

Walkthrough

A new documentation file is introduced that guides developers through implementing webhook support for custom XenForo content types, including database schema creation, entity registration, webhook event handlers, and API payload configuration. Corresponding navigation entry added to the documentation site structure.

Changes

Cohort / File(s) Summary
Documentation addition
docs/webhooks-and-events.md
New comprehensive guide covering webhook implementation for custom content types: database tables, entities, content type registration, webhook event handlers, API result data setup, custom event creation, and usage examples.
Navigation update
mkdocs.yml
Adds "Advanced concepts" subsection under Developers with "Webhook & events" navigation entry linking to the new documentation file.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarises the main change: comprehensive documentation on implementing webhook support, including setup, event handlers, and custom events.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@docs/webhooks-and-events.md`:
- Around line 19-36: Add missing blank lines before and after headings and
fenced code blocks (e.g., the "## Before you start" heading and the ```php
title="setup.php"``` block that contains the public function installStep1()) so
each heading and code fence is separated by a blank line per markdownlint rules
(MD022/MD031/MD047), and ensure the file ends with a single trailing newline;
apply the same spacing fixes to the other affected sections noted (around the
blocks at the other referenced ranges).
- Line 2: The sentence "Webhooks can be helpful for monitoring content types and
events that occur in those content types outside of XenForo in real-time." is
wordy and redundant; replace it with a tighter phrasing such as "Webhooks help
monitor content types and events in real time." Locate the exact sentence in the
document and update it to the simplified version (or an equivalent concise
alternative), keeping "webhooks" and "in real time" but removing the repetitive
"outside of XenForo" phrasing.
- Around line 235-243: In setupApiResultData ensure you guard against a null
User relation: when building the 'User' array passed to $result->includeExtra,
check $this->User for null and set user_id, username, and title to null (or
appropriate defaults) if $this->User is null; update the construction around
$this->User->user_id, $this->User->username, and $this->User->custom_title to
use conditional/null-coalescing checks so no property access occurs on a null
object.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa8a30a and 1acb5b8.

📒 Files selected for processing (2)
  • docs/webhooks-and-events.md
  • mkdocs.yml
🧰 Additional context used
🪛 LanguageTool
docs/webhooks-and-events.md

[style] ~2-~2: This phrase is redundant. Consider using “outside”.
Context: ...vents that occur in those content types outside of XenForo in real-time. XenForo comes wi...

(OUTSIDE_OF)


[grammar] ~6-~6: This phrase is duplicated. You should probably use “Posts Profile” only once.
Context: ...t can be used for webhooks, such as: - Posts - Profile posts - Profile post comments - Reports - Threads - Use...

(PHRASE_REPETITION)


[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...it. Standard events include: - insert: When a new entity is created - update...

(UNLIKELY_OPENING_PUNCTUATION)


[typographical] ~122-~122: Do not use a colon (:) before a series that is introduced by a preposition (‘to’). Remove the colon or add a noun or a noun phrase after the preposition.
Context: ... XenForo admin control panel. Navigate to: Development -> Content types, click t...

(RP_COLON)


[grammar] ~145-~145: This phrase is duplicated. You should probably use “content type” only once.
Context: ...ndor\Addon ### 3. Phrase linked to the content type - Content type: vendor_addon_notes - Field: phra...

(PHRASE_REPETITION)


[uncategorized] ~207-~207: Loose punctuation mark.
Context: ...et's examine each method: - getEvents: This method returns an array of event n...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~208-~208: Loose punctuation mark.
Context: ...m report event as well. - getEventHint: This provides descriptive text for each...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~209-~209: Loose punctuation mark.
Context: ...e admin control panel. - getEntityWith: This specifies which relations should b...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~229-~229: Loose punctuation mark.
Context: ... - $structure->behaviors['XF:Webhook']: This adds the webhook behaviour to the ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~230-~230: Loose punctuation mark.
Context: ... operations. - $structure->contentType: This specifies the content type identif...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~248-~248: Loose punctuation mark.
Context: ... ], ]); } ``` - includeColumn(): Specifies which columns from the entity...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~249-~249: Loose punctuation mark.
Context: ... the webhook payload. - includeExtra(): Allows you to include additional data, ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~272-~272: Possible missing comma found.
Context: ...is done by directly calling the webhook system rather than relying on the automatic tr...

(AI_HYDRA_LEO_MISSING_COMMA)


[uncategorized] ~319-~319: Loose punctuation mark.
Context: ...takes these parameters: - contentType: The content type identifier (vendor_add...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.18.1)
docs/webhooks-and-events.md

1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


19-19: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


32-32: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


64-64: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


119-119: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


133-133: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


139-139: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


145-145: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


151-151: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


211-211: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


213-213: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


232-232: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


234-234: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


251-251: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


253-253: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


271-271: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


327-327: Files should end with a single newline character

(MD047, single-trailing-newline)

🔇 Additional comments (1)
mkdocs.yml (1)

21-22: Navigation entry looks good.

The new “Advanced concepts → Webhook & events” entry is well placed and consistent with the structure.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@@ -0,0 +1,327 @@
# Webhooks and events
Webhooks can be helpful for monitoring content types and events that occur in those content types outside of XenForo in real-time.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Tighten the wording to avoid redundancy.

“Outside of XenForo in real-time” is repetitive; simplify for clarity.

✏️ Suggested edit
-Webhooks can be helpful for monitoring content types and events that occur in those content types outside of XenForo in real-time.
+Webhooks can be helpful for monitoring content types and events that occur outside XenForo in real time.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Webhooks can be helpful for monitoring content types and events that occur in those content types outside of XenForo in real-time.
Webhooks can be helpful for monitoring content types and events that occur outside XenForo in real time.
🧰 Tools
🪛 LanguageTool

[style] ~2-~2: This phrase is redundant. Consider using “outside”.
Context: ...vents that occur in those content types outside of XenForo in real-time. XenForo comes wi...

(OUTSIDE_OF)

🤖 Prompt for AI Agents
In `@docs/webhooks-and-events.md` at line 2, The sentence "Webhooks can be helpful
for monitoring content types and events that occur in those content types
outside of XenForo in real-time." is wordy and redundant; replace it with a
tighter phrasing such as "Webhooks help monitor content types and events in real
time." Locate the exact sentence in the document and update it to the simplified
version (or an equivalent concise alternative), keeping "webhooks" and "in real
time" but removing the repetitive "outside of XenForo" phrasing.

Comment on lines +19 to +36
## Before you start
Before you can begin adding webhooks to your addon, you should understand when webhooks are actually fired in XenForo.

XenForo's webhook system is built to notify external services when certain events occur. Each content type can have various events associated with it. Standard events include:

- `insert`: When a new entity is created
- `update`: When an existing entity is updated
- `delete`: When an entity is deleted

However, you can also create custom events beyond these standard ones.

Let's walk through the process of creating a content type that supports webhooks:

### Create a new database table
First, set up a database table and an entity for that table. Add the following to your `Setup.php` file:

```php title="setup.php"
public function installStep1(): void
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix markdownlint spacing and trailing newline.

Multiple headings/fenced blocks lack surrounding blank lines, and the file is missing a single trailing newline. Please add blank lines around headings and code fences throughout and ensure the file ends with one newline (MD022/MD031/MD047).

🧹 Example adjustment
-## Before you start
-Before you can begin adding webhooks to your addon, you should understand when webhooks are actually fired in XenForo.
+## Before you start
+
+Before you can begin adding webhooks to your addon, you should understand when webhooks are actually fired in XenForo.

-```php title="setup.php"
+```php title="setup.php"

Also applies to: 213-234, 324-327

🧰 Tools
🪛 LanguageTool

[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...it. Standard events include: - insert: When a new entity is created - update...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.18.1)

19-19: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


32-32: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🤖 Prompt for AI Agents
In `@docs/webhooks-and-events.md` around lines 19 - 36, Add missing blank lines
before and after headings and fenced code blocks (e.g., the "## Before you
start" heading and the ```php title="setup.php"``` block that contains the
public function installStep1()) so each heading and code fence is separated by a
blank line per markdownlint rules (MD022/MD031/MD047), and ensure the file ends
with a single trailing newline; apply the same spacing fixes to the other
affected sections noted (around the blocks at the other referenced ranges).

Comment on lines +235 to +243
protected function setupApiResultData(EntityResult $result, $verbosity = self::VERBOSITY_NORMAL, array $options = []): void
{
$result->includeColumn(['note_id', 'title', 'content', 'user_id', 'created_date']);
$result->includeExtra([
'User' => [
'user_id' => $this->User->user_id,
'username' => $this->User->username,
'title' => $this->User->custom_title
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "webhooks-and-events.md" -type f

Repository: xenforo-ltd/docs

Length of output: 89


🏁 Script executed:

cat -n ./docs/webhooks-and-events.md | sed -n '230,250p'

Repository: xenforo-ltd/docs

Length of output: 1170


🏁 Script executed:

find . -name "Notes.php" -type f | head -20

Repository: xenforo-ltd/docs

Length of output: 42


🏁 Script executed:

rg -i "user_id" ./docs/webhooks-and-events.md -B 2 -A 2

Repository: xenforo-ltd/docs

Length of output: 1937


Add a null guard to prevent errors when User relation is null.

user_id is nullable, so $this->User can be null when user_id is null. The example should guard against this to prevent runtime errors.

Proposed fix
 protected function setupApiResultData(EntityResult $result, $verbosity = self::VERBOSITY_NORMAL, array $options = []): void
 {
     $result->includeColumn(['note_id', 'title', 'content', 'user_id', 'created_date']);
-    $result->includeExtra([
-        'User' => [
-            'user_id' => $this->User->user_id,
-            'username' => $this->User->username,
-            'title' => $this->User->custom_title
-        ],
-    ]);
+    if ($this->User)
+    {
+        $result->includeExtra([
+            'User' => [
+                'user_id' => $this->User->user_id,
+                'username' => $this->User->username,
+                'title' => $this->User->custom_title
+            ],
+        ]);
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
protected function setupApiResultData(EntityResult $result, $verbosity = self::VERBOSITY_NORMAL, array $options = []): void
{
$result->includeColumn(['note_id', 'title', 'content', 'user_id', 'created_date']);
$result->includeExtra([
'User' => [
'user_id' => $this->User->user_id,
'username' => $this->User->username,
'title' => $this->User->custom_title
],
protected function setupApiResultData(EntityResult $result, $verbosity = self::VERBOSITY_NORMAL, array $options = []): void
{
$result->includeColumn(['note_id', 'title', 'content', 'user_id', 'created_date']);
if ($this->User)
{
$result->includeExtra([
'User' => [
'user_id' => $this->User->user_id,
'username' => $this->User->username,
'title' => $this->User->custom_title
],
]);
}
}
🤖 Prompt for AI Agents
In `@docs/webhooks-and-events.md` around lines 235 - 243, In setupApiResultData
ensure you guard against a null User relation: when building the 'User' array
passed to $result->includeExtra, check $this->User for null and set user_id,
username, and title to null (or appropriate defaults) if $this->User is null;
update the construction around $this->User->user_id, $this->User->username, and
$this->User->custom_title to use conditional/null-coalescing checks so no
property access occurs on a null object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant